package com.pfs.internal.timestamp.actions;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrTokenizer;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.pfs.internal.timestamp.entities.CardHolder;
import com.pfs.internal.timestamp.entities.History;
import com.pfs.internal.timestamp.entities.Leave;
import com.pfs.internal.timestamp.entities.TimeStamp;
import com.pfs.internal.timestamp.entities.TrackDay;
import com.pfs.internal.timestamp.reports.PfsExcel;
import com.pfs.internal.timestamp.reports.TrackReportExcel;
import com.pfs.internal.timestamp.services.TrackService;
import com.pfs.internal.timestamp.utils.Formater;

@SuppressWarnings("serial")
public class TimeStampAction extends ActionSupport {

	private String account;
	private Date fromDate;
	private Date toDate;
	private int month;
	private int year;
	private List<History> histories;
	private List<TrackDay> trackDays;
	private List<TimeStamp> timeStamps;
	private List<CardHolder> cardHolders;
	private Map<String, Object> mapParams;
	private List<Leave> leaves;
	private List<Date> outDates;
	private String reportName;
	private boolean handOnly;
	private String exceptDates;
	private String addedDates;
	private InputStream inputStream;
	Map<String, Object> session = ActionContext.getContext().getSession();

	@Action(value = "ts-track-search-list", results = { @Result(name = "success", type = "json") })
	public String searchTracks() {
		WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());
		TrackService trackService = (TrackService) context.getBean("trackService");
		buildParams1();
		this.histories = trackService.searchTracksByHistory(mapParams);
		// this.cardHolders = trackService.searchTracksByCardHolder(mapParams);
		// System.out.println(cardHolders.size());
		return SUCCESS;
	}

	@Actions({ @Action(value = "ts-report"), @Action(value = "ts-report-detail") })
	public String init() {
		Calendar calendar = Calendar.getInstance();
		month = calendar.get(Calendar.MONTH);
		year = calendar.get(Calendar.YEAR);
		return SUCCESS;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Action(value = "ts-track-calc-list", results = { @Result(name = "success", type = "json") })
	public String calculateTracks() {
		// get list of myleaves from session
		Map session = ActionContext.getContext().getSession();
		if (session.containsKey(UploadAction.UPLOAD_LEAVES) && session.get(UploadAction.UPLOAD_LEAVES) != null) {
			leaves = (List<Leave>) session.get(UploadAction.UPLOAD_LEAVES);
		} else {
			leaves = new ArrayList<Leave>();
		}
		WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());
		TrackService trackService = (TrackService) context.getBean("trackService");
		buildParams2();
		this.trackDays = trackService.calculateTrackDays(mapParams, leaves, outDates);
		this.setTimeStamps(trackService.calculateTimeStamps(this.trackDays));
		return SUCCESS;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Action(value = "ts-track-calc-detail-list", results = { @Result(name = "success", type = "json") })
	public String calculateTracksDetail() {
		// get list of myleaves from session
		Map session = ActionContext.getContext().getSession();
		if (session.containsKey(UploadAction.UPLOAD_LEAVES) && session.get(UploadAction.UPLOAD_LEAVES) != null) {
			leaves = (List<Leave>) session.get(UploadAction.UPLOAD_LEAVES);
		} else {
			leaves = new ArrayList<Leave>();
		}
		WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());
		TrackService trackService = (TrackService) context.getBean("trackService");
		buildParams2();
		this.setTrackDays(trackService.calculateTrackDays(mapParams, leaves, outDates));
		session.put(TRACKS_RESULT, this.trackDays);
		return SUCCESS;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Action(value = "ts-leaves-load-list", results = { @Result(name = "success", type = "json") })
	public String reloadLeaves() {
		Map session = ActionContext.getContext().getSession();
		if (session.containsKey(UploadAction.UPLOAD_LEAVES)) {
			this.leaves = (List<Leave>) session.get(UploadAction.UPLOAD_LEAVES);
		}
		return SUCCESS;
	}

	@SuppressWarnings("unchecked")
	@Action(value = "ts-report-trackday", results = { @Result(name = "success", type = "stream", params = { "contentType", "application/zip", "contentDisposition", "attachment;filename=${reportName}.zip", "inputName", "inputStream", "allowCaching", "true", "bufferSize", "4096" }) })
	public String export() {
		if (session.containsKey(TRACKS_RESULT)) {
			this.trackDays = (List<TrackDay>) session.get(TRACKS_RESULT);
		} else
			this.trackDays = new ArrayList<TrackDay>();
		Map<String, Object> search = new HashMap<String, Object>();
		search.put("report_code", TRACKS_REPORT_CODE);
		TrackReportExcel trackReportExcel = new TrackReportExcel();
		trackReportExcel.setDtls(this.trackDays);
		PfsExcel<TrackReportExcel> excel = new PfsExcel<TrackReportExcel>(search, trackReportExcel);
		try {
			inputStream = new ByteArrayInputStream(excel.getReport());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return SUCCESS;
	}

	private void buildParams1() {
		this.mapParams = new HashMap<String, Object>();
		this.mapParams.put(ACCOUNT, account);
		this.mapParams.put(HAND_ONLY, handOnly);
		this.mapParams.put(FROM_DATE, fromDate);
		this.mapParams.put(TO_DATE, toDate);
	}

	private void buildParams2() {
		this.mapParams = new HashMap<String, Object>();
		this.mapParams.put(ACCOUNT, account);
		this.mapParams.put(HAND_ONLY, handOnly);
		Calendar c = Calendar.getInstance();
		c.set(Calendar.MONTH, month - 1);
		c.set(Calendar.YEAR, year);
		c.set(Calendar.DAY_OF_MONTH, 1);
		fromDate = c.getTime();
		int maxDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, maxDay);
		toDate = c.getTime();
		this.mapParams.put(FROM_DATE, fromDate);
		this.mapParams.put(TO_DATE, toDate);
		// relax dates
		Map<String, Date> outDates = new HashMap<String, Date>();
		// satudays, sundays
		c.set(Calendar.DAY_OF_MONTH, 0);
		for (int co = 0; co < maxDay; co++) {
			c.add(Calendar.DATE, 1);
			if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
				Date date = c.getTime();
				outDates.put(Formater.date2str(date), date);
			}
		}
		// Added date (ngay lam them cuoi tuan)
		int[] addedDays = getDayOfMonth(this.addedDates);
		for (int i : addedDays) {
			c.set(Calendar.DAY_OF_MONTH, i);
			Date date = c.getTime();
			String key = Formater.date2str(date);
			if (outDates.containsKey(key)) {
				outDates.remove(key);
			}
		}
		// Except date (ngay nghi bu trong tuan)
		int[] excepDays = getDayOfMonth(this.exceptDates);
		for (int i : excepDays) {
			c.set(Calendar.DAY_OF_MONTH, i);
			Date date = c.getTime();
			String key = Formater.date2str(date);
			if (!outDates.containsKey(key)) {
				outDates.put(key, date);
			}
		}
		// convert map to list
		this.outDates = new ArrayList<Date>(outDates.values());
	}

	private int[] getDayOfMonth(String strDates) {
		if (StringUtils.isBlank(strDates)) {
			return new int[0];
		}
		StrTokenizer st = new StrTokenizer(strDates, ",");
		// do not add empty tokens
		st.setIgnoreEmptyTokens(true);
		// get token list
		String[] strArr = st.getTokenArray();
		int[] ret = new int[strArr.length];
		int i = 0;
		for (String string : strArr) {
			ret[i] = Integer.parseInt(string.trim());
			i++;
		}
		return ret;
	}

	@Action(value = "ts-report-export", results = { @Result(name = "success", type = "stream", params = { "contentType", "application/zip", "contentDisposition", "attachment;filename=${reportName}.zip", "inputName", "inputStream", "allowCaching", "true", "bufferSize", "4096" }) })
	public String export2() {
		return SUCCESS;
	}

	public Map<String, Object> getSession() {
		return session;
	}

	public void setSession(Map<String, Object> session) {
		this.session = session;
	}

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}

	public List<History> getHistories() {
		return histories;
	}

	public void setHistories(List<History> histories) {
		this.histories = histories;
	}

	public static final String ACCOUNT = "account";
	public static final String FROM_DATE = "fromDate";
	public static final String TO_DATE = "toDate";
	public static final String HAND_ONLY = "handOnly";
	public static final String TRACKS_RESULT = "tracksResult";
	public static final String TRACKS_REPORT_CODE = "trackday_report";

	public Date getFromDate() {
		return fromDate;
	}

	public void setFromDate(Date fromDate) {
		this.fromDate = fromDate;
	}

	public Date getToDate() {
		return toDate;
	}

	public void setToDate(Date toDate) {
		this.toDate = toDate;
	}

	public Map<String, Object> getMapParams() {
		return mapParams;
	}

	public void setMapParams(Map<String, Object> mapParams) {
		this.mapParams = mapParams;
	}

	public List<CardHolder> getCardHolders() {
		return cardHolders;
	}

	public void setCardHolders(List<CardHolder> cardHolders) {
		this.cardHolders = cardHolders;
	}

	public List<TrackDay> getTrackDays() {
		return trackDays;
	}

	public void setTrackDays(List<TrackDay> trackDays) {
		this.trackDays = trackDays;
	}

	public List<Leave> getLeaves() {
		return leaves;
	}

	public void setLeaves(List<Leave> leaves) {
		this.leaves = leaves;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public String getReportName() {
		return reportName;
	}

	public void setReportName(String reportName) {
		this.reportName = reportName;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public List<TimeStamp> getTimeStamps() {
		return timeStamps;
	}

	public void setTimeStamps(List<TimeStamp> timeStamps) {
		this.timeStamps = timeStamps;
	}

	public List<Date> getOutDates() {
		return outDates;
	}

	public void setOutDates(List<Date> outDates) {
		this.outDates = outDates;
	}

	public String getExceptDates() {
		return exceptDates;
	}

	public void setExceptDates(String exceptDates) {
		this.exceptDates = exceptDates;
	}

	public String getAddedDates() {
		return addedDates;
	}

	public void setAddedDates(String addedDates) {
		this.addedDates = addedDates;
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	public boolean isHandOnly() {
		return handOnly;
	}

	public void setHandOnly(boolean handOnly) {
		this.handOnly = handOnly;
	}

}
